import numpy as np
from collections import Counter

class KNearestNeighbors:
    """
    K近邻分类器实现
    基于距离度量和多数表决原则进行分类
    """
    
    def __init__(self, k=3):
        self.k = k  # 设置近邻数量
        self.X_train = None  # 训练特征数据存储
        self.y_train = None  # 训练标签数据存储
    
    def fit(self, X, y):
        """
        训练模型 - 存储训练数据集
        参数:
        X: 训练特征数据，形状为(n_samples, n_features)的numpy数组
        y: 训练标签数据，形状为(n_samples,)的numpy数组
        """
        self.X_train = X  # 存储训练特征
        self.y_train = y  # 存储训练标签
    
    def predict(self, X):
        """
        预测新样本的类别标签
        """
        predictions = []  # 存储预测结果
        
        # 遍历每个测试样本
        for x in X:
            # 计算当前测试样本与所有训练样本的欧氏距离
            # 使用广播机制进行向量化计算
            distances = np.sqrt(np.sum((self.X_train - x) ** 2, axis=1))
            
            # 获取距离最小的k个样本的索引
            k_indices = np.argsort(distances)[:self.k]
            
            # 提取k个最近邻样本的标签
            k_nearest_labels = self.y_train[k_indices]
            
            # 使用多数表决法确定最终类别
            # Counter统计标签出现频率，most_common(1)返回出现次数最多的标签及其计数
            most_common = Counter(k_nearest_labels).most_common(1)
            
            # 将预测结果添加到列表中
            predictions.append(most_common[0][0])
        
        # 将预测结果转换为numpy数组返回
        return np.array(predictions)


if __name__ == "__main__":
    # 设置随机种子以确保结果可重现
    np.random.seed(42)
    
    # 生成训练数据
    # 100个样本，每个样本2个特征，符合标准正态分布
    X_train = np.random.randn(100, 2)
    
    # 生成训练标签，二分类问题（0和1）
    y_train = np.random.randint(0, 2, 100)
    
    # 创建KNN分类器实例，设置k=3
    knn = KNearestNeighbors(k=3)
    
    # 训练模型 - 存储训练数据
    knn.fit(X_train, y_train)
    
    # 生成测试数据
    # 5个测试样本，每个样本2个特征
    X_test = np.random.randn(5, 2)
    
    # 对测试数据进行预测
    predictions = knn.predict(X_test)
    
    # 输出预测结果
    print("预测结果:", predictions)
